using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Reflection;
using System.Diagnostics;
using SimpleReminder.Properties;
using SimpleUtils;
using SimpleUtils.Win;
using System.Runtime.InteropServices;
using AgentObjects;

namespace SimpleReminder
{
    public partial class frmMain : frmBase
    {
        public frmMain()
        {
            InitializeComponent();

            InitForm();
        }

        private void InitForm()
        {
            SetStatusVersion();
            
            MyEvents.Load();
            
            Utils.InitStatusComboBox(cboStatus.Items);
            cboStatus.SelectedIndex = 0;

            if (Settings.Default.TimerInterval >= 100)
            {
                Timer.Interval = (int) Settings.Default.TimerInterval;
            }
        }

        #region Status
        public void SetStatusVersion()
        {
            statusVersion.Text = Assembly.GetEntryAssembly().GetName().Version.ToString();
        }

        public void SetStatusText(string info)
        {
            SetStatusText(info, true);
        }

        public void SetStatusText(string info, bool doEvents)
        {
            if (String.IsNullOrEmpty(info)) info = "Ready.";
            statusInfo.Text = info;
            if (doEvents) Application.DoEvents();
        }

        public void InitProgress(int min, int max)
        {
            statusProgress.Maximum = max;
            statusProgress.Minimum = min;
        }

        public void SetProgress(int val)
        {
            SetProgress(val, true);
        }

        public void SetProgress(int val, bool doEvents)
        {
            if (val < statusProgress.Minimum) val = statusProgress.Minimum;
            if (val > statusProgress.Maximum) val = statusProgress.Maximum;
            statusProgress.Value = val;

            if (val == statusProgress.Minimum)
            {
                statusProgress.Visible = true;
            }
            else if (val == statusProgress.Maximum)
            {
                statusProgress.Visible = false;
            }
            if (doEvents)
                Application.DoEvents();
        }

        public void ResetProgress()
        {
            statusProgress.Visible = false;
            InitProgress(0, 100);
        }

        #endregion Status

        //private bool _exitApp = false;
        private void mnuExit_Click(object sender, EventArgs e)
        {
            //_exitApp = true;
            Application.Exit();
        }

        private void mnuAbout_Click(object sender, EventArgs e)
        {
            Utils.ShowAbout();
        }

        private void mnuHome_Click(object sender, EventArgs e)
        {
            SimpleDotNet.OpenWebSite();
        }

        private void mnuDiscussion_Click(object sender, EventArgs e)
        {
            SimpleDotNet.OpenDiscussionWebSite();
        }

        private void mnuCheckForUpdate_Click(object sender, EventArgs e)
        {
            Utils.CheckForUpdate(false);
        }

        private void mnuOptions_Click(object sender, EventArgs e)
        {
            frmOptions frm = new frmOptions();
            frm.ShowDialog();
        }

        private void mnuDemo_Click(object sender, EventArgs e)
        {
            frmDemo frm = new frmDemo();
            frm.ShowDialog();
        }

        private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            MyEvents.Save();

            switch (e.CloseReason)
            {
                case CloseReason.UserClosing:
                    this.WindowState = FormWindowState.Minimized;
                    e.Cancel = true;
                    return;
                default:
                    break;
            }

            Timer.Enabled = false;
            if(backgroundWorker1.IsBusy)
                backgroundWorker1.CancelAsync();
            Application.DoEvents();
        }

        private void cboStatus_SelectedIndexChanged(object sender, EventArgs e)
        {
            MyEvents.EventStatus es = Utils.ParseEventStatus(cboStatus.SelectedItem.ToString());
            switch (es)
            {
                case MyEvents.EventStatus.Active:
                    btnEnable.Enabled = false;
                    btnDisable.Enabled = true;
                    break;
                case MyEvents.EventStatus.Disabled:
                    btnEnable.Enabled = true;
                    btnDisable.Enabled = false;
                    break;
                default:
                    btnEnable.Enabled = false;
                    btnDisable.Enabled = false;
                    break;
            }

            RefreshData();
        }

        private delegate void RefreshDataDelegate();

        private void RefreshDataInternal()
        {
            MyEvents.EventStatus es = Utils.ParseEventStatus(cboStatus.SelectedItem.ToString());
            dgvEvents.AutoGenerateColumns = false;
            DataView dvEvents = MyEvents.GetEvents(es);
            dgvEvents.DataSource = dvEvents;

            dgvEvents.Columns["gcLastLastRunTime"].Visible = Settings.Default.ShowLastLastRunTime;
        }

        public void RefreshData()
        {
            if (this.InvokeRequired)
            {
                RefreshDataDelegate rdd = new RefreshDataDelegate(RefreshDataInternal);
                this.Invoke(rdd);
            }
            else
            {
                RefreshDataInternal();
            }
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            DataRow dr = MyEvents.NewEvent();
            frmEvent frm = new frmEvent(dr);
            if (frm.ShowDialog() == DialogResult.OK)
            {
            }
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            if (Settings.Default.StartupMinimized)
            {
                this.WindowState = FormWindowState.Minimized;
                //SetVisible(false);
            }
        }

        private DataRowView[] GetSelectedRows()
        {
            DataRowView[] drvs = null;
            if (dgvEvents.SelectedRows.Count < 1) return drvs;

            drvs = new DataRowView[dgvEvents.SelectedRows.Count];
            for (int i = 0; i < dgvEvents.SelectedRows.Count; i++)
            {
                drvs[i] = dgvEvents.SelectedRows[i].DataBoundItem as DataRowView;
            }

            return drvs;
        }

        private void btnDelete_Click(object sender, EventArgs e)
        {
            if (dgvEvents.SelectedRows.Count < 1)
            {
                SimpleMessage.ShowInfo("Please select event to delete.");
                return;
            }

            try
            {
                if (SimpleMessage.Confirm("Are you sure to delete selected event(s)?") == DialogResult.Yes)
                {
                    DataRowView[] drvs = GetSelectedRows();
                    for (int i = 0; i < drvs.Length; i++)
                    {
                        if (drvs[i] != null)
                        {
                            MyEvents.DeleteEvent(drvs[i].Row);
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                SimpleMessage.ShowException(ex);
            }

        }

        private void btnEdit_Click(object sender, EventArgs e)
        {
            if (dgvEvents.SelectedRows.Count < 1)
            {
                SimpleMessage.ShowInfo("Please select event to edit.");
                return;
            }

            DataRowView drv = dgvEvents.SelectedRows[0].DataBoundItem as DataRowView;
            EditRow(drv);
        }

        private void dgvEvents_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            if (dgvEvents.CurrentRow != null)
            {
                DataRowView drv = dgvEvents.CurrentRow.DataBoundItem as DataRowView;
                EditRow(drv);
            }
        }

        private void EditRow(DataRowView drv)
        {
            if (drv != null)
            {
                frmEvent frm = new frmEvent(drv.Row);
                if (frm.ShowDialog() == DialogResult.OK)
                {
                    //RefreshData();
                }
            }
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            MyEvents.Save();
            SetStatusText("Save OK.");
        }

        private void btnEnable_Click(object sender, EventArgs e)
        {
            if (dgvEvents.SelectedRows.Count < 1)
            {
                SimpleMessage.ShowInfo("Please select event to enable.");
                return;
            }

            DataRowView[] drvs = GetSelectedRows();
            for (int i = 0; i < drvs.Length; i++)
            {
                if (drvs[i] != null)
                {
                    drvs[i][MyEvents.COL_STATUS] = MyEvents.EventStatus.Active;
                    drvs[i].EndEdit();
                }
            }
        }

        private void btnDisable_Click(object sender, EventArgs e)
        {
            if (dgvEvents.SelectedRows.Count < 1)
            {
                SimpleMessage.ShowInfo("Please select event to disable.");
                return;
            }

            DataRowView[] drvs = GetSelectedRows();
            for (int i = 0; i < drvs.Length; i++)
            {
                if (drvs[i] != null)
                {
                    drvs[i][MyEvents.COL_STATUS] = MyEvents.EventStatus.Disabled;
                    drvs[i].EndEdit();
                }
            }
        }

        private delegate void SetGridViewCurrentCellDelegate(int rowIndex);

        private void SetGridViewCurrentCellInternal(int rowIndex)
        {
            dgvEvents.CurrentCell = dgvEvents.Rows[rowIndex].Cells[1];
        }

        public void SetGridViewCurrentCell(int rowIndex)
        {
            if (this.InvokeRequired)
            {
                SetGridViewCurrentCellDelegate d = new SetGridViewCurrentCellDelegate(SetGridViewCurrentCellInternal);
                this.Invoke(d, new object[] { rowIndex });
            }
            else
            {
                SetGridViewCurrentCellInternal(rowIndex);
            }
        }

        private void dgvEvents_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
        {
            SetGridViewCurrentCell(e.RowIndex);
        }

        private void frmMain_SizeChanged(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Minimized)
            {
                SetVisible(false);               
            }
            else
            {
                //SetVisible(true);
            }
        }

        [DllImport("user32.dll")]
        public static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);

        private void SetVisible(bool visible)
        {
            this.Visible = visible;
            notifyIcon1.Visible = !visible;

            if (visible)
            {
                this.WindowState = FormWindowState.Maximized;
                SwitchToThisWindow(this.Handle, true);
            }
        }

        private void SetStatusLastTimeTick()
        {
            statusLastTimeTick.Text = String.Format("{0:HH:mm:ss}", DateTime.Now);
        }

        bool _firstTime = true;
        private void Timer_Tick(object sender, EventArgs e)
        {
            if (backgroundWorker1.IsBusy || Program.MainForm == null || Program.MainForm.IsEditing)
            {
                Application.DoEvents();
                return;
            }

            SetStatusLastTimeTick();
            backgroundWorker1.RunWorkerAsync();
            SetStatusText(null);
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {            
            HandleEvents();

            if (_firstTime)
            {
                _firstTime = false;
            }
        }

        bool _isEditing = false;
        public bool IsEditing
        {
            get { return _isEditing; }
            set { _isEditing = value; }
        }

        private void HandleEvents()
        {
            DataTable dt = MyEvents.EventsTable;
            bool statusChanged = false;
            int count = 0;

            for (int i = 0; i < dt.Rows.Count; i++)
            {
                DataRow dr = dt.Rows[i];
                MyEvents.EventStatus es = Utils.ParseEventStatus(dr[MyEvents.COL_STATUS] as string);

                if (es != MyEvents.EventStatus.Active) continue;

                EventBase eb = MyEvents.CreateEvent(dr, _firstTime);
                if (eb != null)
                {
                    if (eb.IsTimeToRun())
                    {
                        eb.Run();
                        count++;
                        statusChanged |= eb.StatusChanged;
                        //Application.DoEvents();
                    }
                }

                if (backgroundWorker1.CancellationPending) 
                    break;
            }//end for

            if (count > 0)
            {
                MyEvents.Save();
            }

            if (statusChanged && this.Visible && !IsEditing)
            {
                RefreshData();
            }
        }

        public delegate void RunAgentInternalDelegate(string characterID, string agentPath, short agentTop, short agentLeft, 
            string animation, string speech);

        private void RunAgentInternal(string characterID, string agentPath, short agentTop, short agentLeft, 
            string animation, string speech)
        {
            CloseAgent(characterID);
            frmRunAgent f = new frmRunAgent(characterID, agentPath, agentTop, agentLeft, animation, speech);
            f.Show();
        }

        public bool CloseAgent(string characterID)
        {
            frmRunAgent f = frmRunAgent.GetRunningForm(characterID);
            bool closed = true;
            if (f != null)
            {
                f.ClosePending = true;
                if (f.InPlaying)
                {
                    closed = false;
                }
                else
                {
                    f.Close();
                    f.Dispose();
                }
            }
            return closed;
        }

        public void RunAgent(string characterID, string agentPath, short agentTop, short agentLeft, string animation, string speech)
        {
            if (this.InvokeRequired)
            {
                RunAgentInternalDelegate raid = new RunAgentInternalDelegate(RunAgentInternal);
                this.Invoke(raid, new object[] {characterID, agentPath, agentTop, agentLeft, animation, speech} );
            }
            else
            {
                RunAgentInternal(characterID, agentPath, agentTop, agentLeft, animation, speech);
            }
        }

        private void mnuMSAgent_Click(object sender, EventArgs e)
        {
            SimpleProcess.Start(@"http://www.microsoft.com/products/msagent/main.aspx");
        }

        private void cmOpen_Click(object sender, EventArgs e)
        {
            SetVisible(true);
        }

        private void cmExit_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void notifyIcon1_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                SetVisible(true);
            }
        }

        private void cmOptions_Click(object sender, EventArgs e)
        {
            frmOptions f = new frmOptions();
            f.ShowDialog();
        }

        /*
        private void mnuCompactDatabase_Click(object sender, EventArgs e)
        {
            try
            {
                this.Cursor = Cursors.WaitCursor;
                SetStatusText("Compacting database ...");
                Utils.CompactDatabase();
            }
            catch (Exception ex)
            {
                SimpleMessage.ShowException(ex);
            }
            finally
            {
                this.Cursor = Cursors.Default;
                SetStatusText(null);
            }
        }
        */
    }//end of class
}